package de.hbrs.ooka.dhs.main;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.io.File;

import de.hbrs.ooka.dhs.api.DHSComponent;
import de.hbrs.ooka.dhs.entities.DHSComponentEntity;
import de.hbrs.ooka.dhs.persistence.DHSComponentEntityDatabaseManager;

public class DHSComponentManager {

	private static Map<String, DHSComponent> installedDhsComponents;
	private static Map<String, DHSComponentLauncher> activeDhsComponentLaunchers;
	private static DHSComponentEntityDatabaseManager dhsComponentEntityDatabaseManager;

	public static void main(String[] args) {

		System.out.println("DHSComponentLauncher");
		System.out.println("--------------------");

		dhsComponentEntityDatabaseManager = new DHSComponentEntityDatabaseManager();
		loadComponents();

		System.out.println("Previous state restored. Runtime is ready!");

		Scanner scanner = new Scanner(System.in);
		String[] parameters;

		while (true) {
			parameters = scanner.nextLine().split(" ");

			if (parameters[0].equals("exit")) {
				System.out.println("Stopping all components ...");
				for (String dhsComponentKey : activeDhsComponentLaunchers.keySet()) {
					stopComponent(dhsComponentKey, true);
				}
				installedDhsComponents = null;
				activeDhsComponentLaunchers = null;
				System.out.println("Exiting runtime.");
				break;
			}

			else if (parameters[0].equals("list")) {
				if (installedDhsComponents.size() > 0) {
					System.out.println("Installed components:");
					System.out.println("---------------------");
					for (String dhsComponentKey : installedDhsComponents.keySet()) {
						System.out.println(dhsComponentKey+ (activeDhsComponentLaunchers.containsKey(dhsComponentKey) ? " (running)": ""));
					}
				} else {
					System.out.println("No components installed.");
				}
			}

			else if (parameters[0].equals("install")) {
				if (!installedDhsComponents.containsKey(parameters[1])) {
					installComponent(parameters[1], parameters[2], true);
				} else {
					System.out.println("There is already a component installed with that name!");
				}
			}

			else if (parameters[0].equals("start")) {
				if (installedDhsComponents.containsKey(parameters[1])) {
					if (!activeDhsComponentLaunchers.containsKey(parameters[1])) {
						startComponent(parameters[1], true);
					} else {
						System.out.println("Component is already running.");
					}
				} else {
					System.out.println("No such component installed.");
				}
			}

			else if (parameters[0].equals("stop")) {
				if (activeDhsComponentLaunchers.containsKey(parameters[1])) {
					System.out.println("Stopping component ...");
					stopComponent(parameters[1], true);
				} else {
					System.out.println("No such component running.");
				}
			}

			else if (parameters[0].equals("uninstall")) {
				if (installedDhsComponents.containsKey(parameters[1])) {
					if (activeDhsComponentLaunchers.containsKey(parameters[1])) {
						System.out.println("Component is still running and will be stopped now.");
						stopComponent(parameters[1], true);
					}
					installedDhsComponents.remove(parameters[1]);
					DHSComponentEntity dhsComponentEntity = dhsComponentEntityDatabaseManager.findByName(parameters[1]);
					dhsComponentEntityDatabaseManager.remove(dhsComponentEntity);
					System.out.println("Component successfully uninstalled.");
				} else {
					System.out.println("No such component installed.");
				}
			}

			else {
				System.out.println("Incorrect input.");
			}

		}

		scanner.close();
	}

	protected static void loadComponents() {
		installedDhsComponents = new HashMap<>();
		List<DHSComponentEntity> dhsComponentEntities = dhsComponentEntityDatabaseManager.findAll();
		if (dhsComponentEntities != null && !dhsComponentEntities.isEmpty()) {
			for (DHSComponentEntity dhsComponentEntity : dhsComponentEntities) {
				installComponent(dhsComponentEntity.getName(), dhsComponentEntity.getInstallationPath(), false);
			}
		}

		activeDhsComponentLaunchers = new HashMap<>();
		dhsComponentEntities = dhsComponentEntityDatabaseManager.findAllRunningOrderedByPosition();
		if (dhsComponentEntities != null && !dhsComponentEntities.isEmpty()) {
			for (DHSComponentEntity dhsComponentEntity : dhsComponentEntities) {
				startComponent(dhsComponentEntity.getName(), false);
			}
		}
	}

	protected static void installComponent(String key, String path, boolean record) {
		try {
			URL url = new File(path).toURI().toURL();
			URL[] URLArray = new URL[1];
			URLArray[0] = url;
			URLClassLoader urlClassLoader = new URLClassLoader(URLArray);
			Class<?> loadedClass = urlClassLoader.loadClass(key);
			urlClassLoader.close();
			boolean startMethod = false, stopMethod = false;
			for (Method method : loadedClass.getMethods()) {
				if (method.getName().equals("start")) {
					startMethod = true;
				}
				if (method.getName().equals("stop")) {
					stopMethod = true;
				}
			}
			if (startMethod && stopMethod) {
				DHSComponent newDhsComponent = (DHSComponent) loadedClass.newInstance();
				installedDhsComponents.put(key, newDhsComponent);
				if (record) {
					DHSComponentEntity dhsComponentEntity = new DHSComponentEntity();
					dhsComponentEntity.setName(key);
					dhsComponentEntity.setInstallationPath(path);
					dhsComponentEntity.setRunning(false);
					dhsComponentEntityDatabaseManager.create(dhsComponentEntity);
				}
				System.out.println("Component " + key + " successfully installed.");
			}
		} catch (Exception e) {
			System.out.println("An exception occurred during the installation process!");
			e.printStackTrace();
		}
	}

	protected static void startComponent(String key, boolean record) {
		System.out.println("Starting component " + key);
		DHSComponentLauncher dhsComponentLauncher = new DHSComponentLauncher();
		dhsComponentLauncher.setDhsComponent(installedDhsComponents.get(key));
		dhsComponentLauncher.start();
		activeDhsComponentLaunchers.put(key, dhsComponentLauncher);
		if (record) {
			DHSComponentEntity dhsComponentEntity = dhsComponentEntityDatabaseManager.findByName(key);
			dhsComponentEntity.setRunning(true);
			dhsComponentEntity.setPosition(dhsComponentEntityDatabaseManager.getMaxPosition() + 1);
			dhsComponentEntityDatabaseManager.update(dhsComponentEntity);
		}
	}

	protected static void stopComponent(String key, boolean record) {
		activeDhsComponentLaunchers.get(key).end();
		activeDhsComponentLaunchers.remove(key);
		if (record) {
			DHSComponentEntity dhsComponentEntity = dhsComponentEntityDatabaseManager.findByName(key);
			dhsComponentEntity.setRunning(false);
			dhsComponentEntity.setPosition(0);
			dhsComponentEntityDatabaseManager.update(dhsComponentEntity);
		}
	}
}
